#!/usr/bin/env python
#-------------------------------python---------------------pyturtle.py--#
#                                                                       #
#                              Pyturtle                                 #
#                                                                       #
#--Daniele Zambelli--------------GPL------------------------------2007--#

import sys
#from math import * # Also for export
from math import atan2, hypot, pi, cos, sin
from pycart import Plane
import pygrapherror as pyerr

_pyturtle_version = '02.03.02'

class Turtle(object):

  def __init__(self, plane=None):
    if not plane: plane=Plane("Geometria della Tartaruga")
    self._plane = plane
    self._canvas=plane.getcanvas()
    self._createturtle() # da funzione a procedura
    self._canvas.update()
    self._attesa = 0
    self.degrees()
    self._init()
    self._draw_turtle()

  def _init(self):
    """Initialize all variables."""
    self._x = 0
    self._y = 0
    self._angle = 0.0
    self._cos = 1
    self._sin = 0
    self._drawing = 1
    self._width = 1
    self._color = "black"
    self._filling = 0
    self._path = []
    self._tofill = []

  def version(self):
    return _pyturtle_version

  def mainloop(self):
    self._plane.mainloop()

  def after(self, *args):
    self._plane.after(*args)

  def degrees(self, fullcircle=360.0):
    """Translate radians in degree."""
    self._fullcircle = fullcircle
    self._invradian = pi / (fullcircle * 0.5)

  def radians(self):
    """Translate degrees in radians."""
    self.degrees(2.0*pi)

  def reset(self):
    """Reset graphic window."""
    self._init()
    self.clear()

  def clear(self):
    """Clear grapic windows without reset turtle."""
    self.fill(0)
    self._plane.clear()
    self._createturtle()
    self._draw_turtle()

  def tracer(self, attesa):
    """Set a brake for turtle."""
    self._attesa=int(abs(attesa))

  def getpos(self):
    """Set turtle position."""
    return self._x, self._y

  def getplane(self):
    """Return plane where turtle lives."""
    return self._plane

  def forward(self, distance):
    """Move the turtle forward distance step."""
    return self.setpos((self._x + distance * self._cos,
                        self._y + distance * self._sin))

  def back(self, distance):
    """Move the turtle back distance step."""
    return self.forward(-distance)

  def setdir(self, angle):
    """Turn the turtle ad angle direction."""
    self._angle=angle % self._fullcircle
    angle*=self._invradian
    self._cos=cos(angle)
    self._sin=sin(angle)
    self._draw_turtle()

  def getdir(self):
    """Return the turtle direction."""
    return self._angle

  def left(self, angle):
    """Turn the turtle left angle degree."""
    self.setdir((self._angle + angle) % self._fullcircle)

  def right(self, angle):
    """Turn the turtle right angle degree."""
    self.left(-angle)

  def up(self):
    """Lifts the turtle's pen up."""
    self._drawing = 0

  def down(self):
    """Puts the turtle pen down."""
    self._drawing = 1

  def setwidth(self, width):
    """Sets the turtle and pen width."""
    if width>1: self._width = float(width)
    else:       self._width = 1.0
    self._turtledim = (self._width+7, self._width+9, self._width/2+3)
    self._canvas.itemconfigure(self._turtle, arrowshape=self._turtledim)
    self._draw_turtle()

  def getwidth(self):
    """Return the turtle and pen width."""
    return self._width

  def distance(self, (xother, yother)):
    """Return the distance enter turtle and a point."""
    return hypot(self._x-xother, self._y-yother)

  def dirto(self, (xother, yother)):
    """Return the angle enter turtle direction and a point."""
    return ((atan2(yother-self._y, xother-self._x)/self._invradian)
            -self._angle) % self._fullcircle

  def whereis(self, point):
    """Return distance and angle enter turtle and point."""
    return self.distance(point), self.dirto(point)

  def lookat(self, point):
    """Turn turtle towards point."""
    self.left(self.dirto(point))

  def setcolor(self, *color):
    """Sets turtle and pen color."""
    self._color = self._plane.color(color)
    self._canvas.itemconfigure(self._turtle, fill=self._color)
    self._canvas.update()

  def getcolor(self):
    """Gets turtle and pen color."""
    return self._color

  def write(self, arg, move=0):
    """Writes a text from the position of the turtle.""" 
    x, y = self._plane._p2s((self._x, self._y))
    x = x-1 # correction -- calibrated for Windows
    item = self._canvas.create_text(x, y,
                                  text=str(arg), anchor="nw",
                                  fill=self._color)
    if move:
      x0, y0, x1, y1 = self._canvas.bbox(item)
      self.setpos((self._plane._s2x(x1), self._plane._s2y(y1)))
    self._draw_turtle()

  def fill(self, flag):
    """Start or end filling."""
    if self._filling:
      path = tuple(self._path)
      smooth = self._filling < 0
      if len(path) > 2:
        item = self._canvas._create('polygon', path,
                                  {'fill': self._color, 'smooth': smooth})
        self._canvas.lower(item)
      if self._tofill:
        for item in self._tofill:
          self._canvas.itemconfigure(item, fill=self._color)
    self._path = []
    self._tofill = []
    self._filling = flag
    if flag: self._path.append(self._plane._p2s((self._x, self._y)))

  def circle(self, radius, extent=None):
    """Draw a circle starts in turtle position."""
    x0, y0 = self._plane._p2s((self._x, self._y))
    xc = x0 - radius * self._sin
    yc = y0 - radius * self._cos
    item=self._circle(xc, yc, radius, self._angle-90, extent, 'chord')
    x1 = xc + radius * self._sin
    y1 = yc + radius * self._cos
    self._x, self._y = self._plane._s2x(x1), self._plane._s2y(y1)
    self._draw_turtle()
    if self._filling:
      self._path.append(self._plane._p2s((self._x, self._y)))
    return item

  def ccircle(self, radius, extent=None):
    """Draw a circle with center in turtle position."""
    xc, yc = self._plane._p2s((self._x, self._y))
    item=self._circle(xc, yc, radius, self._angle, extent, 'pieslice')
    return item
  
  def _circle(self, xc, yc, radius, start, extent, sty):
    """Draw a circle."""
    if not extent: extent = self._fullcircle
    if radius < 0.0: start = start + 180.0
    out = self._drawing and self._color or ''
    if abs(extent) >= self._fullcircle:
      item = self._canvas.create_oval(xc-radius, yc-radius,
                                    xc+radius, yc+radius,
                                    width=self._width,
                                    outline=out)
    else:
      if not self._filling: sty = 'arc'
      item = self._canvas.create_arc(xc-radius, yc-radius,
                                   xc+radius, yc+radius,
                                   style=sty,
                                   start=start,
                                   extent=extent,
                                   width=self._width,
                                   outline=out)
    if self._filling: self._tofill.append(item)
    self.left(extent)
    return item

  def setpos(self, (x, y)):
    """Move the turtle in (x, y)."""
    x0, y0 = self._plane._p2s((self._x, self._y))
    self._x, self._y = float(x), float(y)
    if self._filling:
      self._path.append(self._plane._p2s((x, y) ))
    if self._drawing:
      x, y = self._plane._p2s((x, y))
      item = self._canvas.create_line(x0, y0, x0, y0,
                                    width=self._width,
                                    capstyle="round",
                                    fill=self._color)
      if self._attesa:                
        dx = float(x) - x0; dy = float(y) - y0
        nhops = int(hypot(dx, dy))
        if nhops:
          dx /=nhops; dy /=nhops
          x1 = x0; y1 = y0
          try:
            for i in range(nhops):
              x1 += dx; y1 += dy
              self._canvas.coords(item, x0, y0, x1, y1)
              self._draw_turtle((x1,y1))
              self._canvas.after(self._attesa)
          except TclError:
            # Probably the window was closed!
            return
      self._canvas.coords(item, x0, y0, x, y)
    else: item=None
    self._draw_turtle()
    return item

  def _createturtle(self):
    """Create a turtle."""
    x, y = self._plane._p2s((0, 0))
    self._turtle = self._canvas.create_line(x+8,y,x,y, arrow='last')

  def _draw_turtle(self, position=None):
    """Draw turtle."""
    if not position: position = self._plane._p2s((self._x, self._y))
    x,y = position
    distance = self._width+7
    dx = distance * self._cos
    dy = distance * self._sin
#  Pen on head:
#    self._canvas.coords(self._turtle, (x-dx, y+dy, x, y))
#  Pen on tail:
    self._canvas.coords(self._turtle, (x, y, x+dx, y-dy))
    self._canvas.update()

  def hide(self):
    """Hide turtle."""
    self._canvas.itemconfigure(self._turtle, arrow='')

  def show(self):
    """Show turtle."""
    self._canvas.itemconfigure(self._turtle, arrow='last')

  def save(self, filename):
    """Save the design."""
    self._plane.save(filename)

if __name__=="__main__":
  tina=Turtle()
  for ang in range(360):
    tina.setcolor(0.7, ang/360., 0.3)
    tina.forward(200)
    tina.up()
    tina.back(200)
    tina.left(1)
    tina.down()
  tina.reset()
  for ang in range(360):
    tina.setcolor(ang/360., 0.7, 0.3)
    tina.forward(200)
    tina.up()
    tina.back(200)
    tina.left(1)
    tina.down()
  tina.reset()
  for ang in range(360):
    tina.setcolor(0.7, 0.3, ang/360.)
    tina.forward(200)
    tina.up()
    tina.back(200)
    tina.left(1)
    tina.down()
  tina.mainloop()
